// Copyright 2017 guangbo. All rights reserved.

//服务管理
package lib_rpc

import (
	//"sync"
	"fmt"
	"gitee.com/goxiang2/server/lib/lib_config"
	"gitee.com/goxiang2/server/lib/lib_watch"
	"log"
	"net"
	"os"
	"sync"
)

type GxService interface {
	Run() error
}

type GxNodeConn struct {
	Info  *lib_config.NodeInfo
	Conn  *Client
	Close bool
}

type GxNode struct {
	Name     string   //自己的节点名
	Server   *Server  //自己rpc服务端
	Services sync.Map //自己的服列表

	WatchClient *lib_watch.WatchClient //watch客户端
	RpcClient   sync.Map               //到其他节点的连接
	CmdService  sync.Map               //消息对应服务名

	// ServiceNode sync.Map               //服务对应节点名
	Mutex       sync.Mutex
	ServiceNode map[string]map[string]bool //服务对应节点名
}

var NodeIntance GxNode

func GetWatchClient() *lib_watch.WatchClient {
	return NodeIntance.WatchClient
}

func connectNode(info *lib_config.NodeInfo) {
	if info.Name == NodeIntance.Name {
		return
	}

	conn, err := Dial("tcp", info.Address)
	isClose := true
	if err != nil {
		isClose = false
		log.Println("connect server fail", info.Address, err)
	}

	NodeIntance.Mutex.Lock()
	for i := 0; i < len(info.Service); i++ {
		s, ok := NodeIntance.ServiceNode[info.Service[i]]
		if ok {
			s[info.Name] = true
		} else {
			s1 := make(map[string]bool)
			s1[info.Name] = true
			NodeIntance.ServiceNode[info.Service[i]] = s1
		}
	}
	NodeIntance.Mutex.Unlock()

	log.Println("connect server ok", info.Name, info.Address)
	NodeIntance.RpcClient.Store(info.Name, &GxNodeConn{info, conn, isClose})
}

func InitNode(client *lib_watch.WatchClient, nodeName string) {
	log.Println("init node", nodeName)
	port := ":9003"

	NodeIntance.Name = nodeName
	NodeIntance.ServiceNode = make(map[string]map[string]bool)
	NodeIntance.Server = NewServer()
	NodeIntance.Services.Range(func(key, value interface{}) bool {
		serviceName := key.(string)
		log.Println("register service", serviceName)
		NodeIntance.Server.RegisterName(serviceName, value)
		go func() {
			err := value.(GxService).Run()
			if err != nil {
				log.Println(err.Error())
				os.Exit(0)
			}
		}()
		return true
	})

	NodeIntance.WatchClient = client
	if NodeIntance.WatchClient != nil {
		// 获取节点配置
		m := lib_config.GetNodeAllConfig(NodeIntance.WatchClient, nodeName)
		for k, v := range m {
			log.Println("load node config, ", nodeName, k, v)
		}

		addr := m["host"] + ":" + m["port"]
		port = ":" + m["port"]

		// 注册节点信息
		go func() {
			info := &lib_config.NodeInfo{
				Name:    NodeIntance.Name,
				Address: addr,
			}

			NodeIntance.Services.Range(func(key, value interface{}) bool {
				info.Service = append(info.Service, key.(string))
				return true
			})

			lib_config.SetRegisterNode(NodeIntance.WatchClient, nodeName, info)
		}()

		go func() {
			// 拉去其他节点信息
			nodes := lib_config.GetAllRegisterNode(NodeIntance.WatchClient)
			for _, v := range nodes {
				connectNode(v)
			}

			// 拉取cmd信息
			cmds := lib_config.GetAllCmdConfig(NodeIntance.WatchClient)
			for k, v := range cmds {
				NodeIntance.CmdService.Store(k, v)
			}
		}()
	}
	l, err := net.Listen("tcp", port)
	if err != nil {
		log.Fatal("listen error:", err)
	}
	NodeIntance.Server.Accept(l)
}

func WatchCmd(k, v string) {
	log.Println("cmd update, ", k, v)
	if v == "" {
		NodeIntance.CmdService.Delete(k)
	} else {
		NodeIntance.CmdService.Store(k, v)
	}
}

func WatchNodeRegister(k, v string) {
	log.Println("node update, ", k, v)
	if v == "" {
		info, ok := NodeIntance.RpcClient.Load(k)
		if ok {
			nodeInfo := info.(*GxNodeConn)
			nodeInfo.Conn.Close()
			nodeInfo.Close = false
			NodeIntance.RpcClient.Delete(k)
		}
	} else {
		info := lib_config.GetRegisterNode(NodeIntance.WatchClient, k)
		if info != nil {
			connectNode(info)
		}
	}
}

//多节点调用此函数，返回提供服务的所有节点，自己处理，例如
// key := fmt.Sprintf("%v:%v", appid, username)
// verifies := lib_rpc.FindRpcConnByService(serviceName)
// if len(verifies) == 0 {
// 	return static.RetServiceStop, nil
// }
// ring := ketama.NewRing(200)
// for k, _ := range verifies {
// 	ring.AddNode(k, 100)
// 	ring.Bake()
// }
// name := ring.Hash(key)
// ret, err := verifies[name].Call(funcName, &req, &rsp)
// return uint16(ret), err
func FindRpcConnByService(serviceName string) map[string]*Client {
	NodeIntance.Mutex.Lock()
	defer NodeIntance.Mutex.Unlock()

	NodeNames, ok := NodeIntance.ServiceNode[serviceName]
	if !ok || len(NodeNames) == 0 {
		return nil
	}

	m := make(map[string]*Client)
	for k, _ := range NodeNames {
		info, ok2 := NodeIntance.RpcClient.Load(k)
		if !ok2 {
			continue
		}

		m[k] = info.(*GxNodeConn).Conn
	}

	return m
}

func AddServiceMethod(cmd uint32, serviceMethod string) {
	NodeIntance.CmdService.Store(cmd, serviceMethod)
}

func FindServiceMethod(cmd uint32) string {
	i, ok := NodeIntance.CmdService.Load(cmd)
	if !ok {
		return ""
	}

	return i.(string)
}

// RegisterService 注册服务
func RegisterService(serviceName, service interface{}) {
	NodeIntance.Services.Store(serviceName, service)
}

// 服务之间的rpc调用
func RpcCall(serviceMethod string, req interface{}, rsp interface{}) (uint32, error) {
	serviceName, _ := splitServiceMethod(serviceMethod)
	_, ok := NodeIntance.Services.Load(serviceName)
	if ok {
		// 内部调用
		return NodeIntance.Server.InternalCall(serviceMethod, req, rsp)
	} else {
		// todo 跨节点
		clients := FindRpcConnByService(serviceName)
		if len(clients) == 0 {
			return 0, fmt.Errorf("not support node rpc")
		}

		//todo 暂时随便选一个，应该有一个分配机制的
		var client *Client = nil
		for _, c := range clients {
			client = c
			break
		}
		return client.Call(serviceMethod, req, rsp)
	}
}

func RpcRawCall(serviceMethod string, reqBuff []byte) (uint32, []byte, error) {
	serviceName, _ := splitServiceMethod(serviceMethod)
	_, ok := NodeIntance.Services.Load(serviceName)
	if ok {
		// 内部调用
		return NodeIntance.Server.RawCall(serviceMethod, reqBuff)
	} else {
		// todo 跨节点
		clients := FindRpcConnByService(serviceName)
		if len(clients) == 0 {
			return 0, nil, fmt.Errorf("not support node rpc")
		}

		//todo 暂时随便选一个，应该有一个分配机制的
		var client *Client = nil
		for _, c := range clients {
			client = c
			break
		}
		return client.RawCall(serviceMethod, reqBuff)
	}
}
